namespace BM.Tools.WebControls.MForm.Navigation
{
    using System;

    using BM.Tools.WebControls.MForm.Navigation.XPath;

    /// <summary>
    /// A navigator for the <see cref="LocationStep" /> locator.
    /// </summary>
    /// <typeparam name="T">
    /// The type of the navigable object.
    /// </typeparam>
    /// <typeparam name="TLocator">
    /// the type of the location step
    /// </typeparam>
    public abstract class LocationStepNavigator<T, TLocator> : Navigator<T, TLocator> where TLocator : LocationStep
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="LocationStepNavigator{T, TLocator}"/> class. 
        /// </summary>
        /// <param name="parent">
        /// The parent.
        /// </param>
        /// <param name="locator">
        /// The locator.
        /// </param>
        protected LocationStepNavigator(INavigator<T> parent, TLocator locator) : base(parent, locator)
        {
        }

        /// <summary>
        /// a location step navigator factory
        /// </summary>
        /// <param name="parent">
        /// The parent.
        /// </param>
        /// <param name="locationStep">
        /// The locationStep.
        /// </param>
        /// <returns>
        /// the instance of the <see cref="LocationStepNavigator{T,TLocator}" />
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// </exception>
        internal static INavigator<T> Create(INavigator<T> parent, LocationStep locationStep)
        {
            var compound = locationStep as CompoundLocationStep;
            if (compound != null)
            {
                return new CompoundLocationStepNavigator<T>(parent, compound);
            }

            var single = locationStep as SingleLocationStep;
            if (single != null)
            {
                return new SingleLocationStepNavigator<T>(parent, single);
            }

            throw new InvalidOperationException("Unknown location step type:" + locationStep.GetType().Name);
        }
    }
}